﻿using System;
using Bricks;
using Bricks.Injecting;
using Bricks.Logging;
using Motar.Modularity;
using Motar.Properties;

namespace Motar
{

    /// <summary>
    /// 
    /// </summary>
    public abstract class BootstrapperBase : DisposableFacadeBase<IContainerFacade>, IBootstrapper
    {

        /// <summary>
        /// 
        /// </summary>
        private readonly object _syncRoot = new object();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="containerFacadeFactory"></param>
        protected BootstrapperBase(Func<IContainerFacade> containerFacadeFactory) :
            base(containerFacadeFactory.Invoke())
        {
        }

        /// <summary>
        /// 
        /// </summary>
        protected object SyncRoot
        {
            get { return _syncRoot; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="runWithDefaultConfiguration"></param>
        public virtual void Run(bool runWithDefaultConfiguration)
        {
            Execute(containerFacade =>
            {
                ILoggerFacade loggerFacade; IModuleCatalog moduleCatalog; IApplicationInitializer applicationInitializer; IModuleManager moduleManager;

                lock (SyncRoot)
                {
                    try
                    {
                        loggerFacade = containerFacade.Resolve<ILoggerFacade>();
                    }
                    catch (Exception exception)
                    {
                        throw new InvalidOperationException(Resources.NullLoggerException, exception);
                    }
                    if (loggerFacade == null)
                    {
                        throw new InvalidOperationException(Resources.NullLoggerException);
                    }
                    loggerFacade.Debug(Resources.LoggerCreatedSuccessfully);

                    //
                    {
                        loggerFacade.Debug(Resources.ConfiguringContainerSingleton);

                        ServiceLocator.Initialize(() => containerFacade);
                    }

                    //
                    loggerFacade.Debug(Resources.CreatingApplicationInitializer);
                    //
                    if (containerFacade.TryResolve<IApplicationInitializer>(out applicationInitializer))
                    {
                        loggerFacade.Debug(Resources.InitializingApplication);

                        applicationInitializer.Execute();
                    }
                    else
                    {
                        loggerFacade.Debug(Resources.ApplicationInitializerNotFound);
                    }

                    //
                    loggerFacade.Debug(Resources.CreatingModuleCatalog);
                    try
                    {
                        moduleCatalog = containerFacade.Resolve<IModuleCatalog>();
                    }
                    catch (Exception exception)
                    {
                        throw new InvalidOperationException(Resources.NullModuleCatalogException, exception);
                    }
                    if (moduleCatalog == null)
                    {
                        throw new InvalidOperationException(Resources.NullModuleCatalogException);
                    }

                    //
                    if (containerFacade.TryResolve<IModuleManager>(out moduleManager))
                    {
                        loggerFacade.Debug(Resources.InitializingModules);

                        moduleManager.Run();
                    }

                    loggerFacade.Debug(Resources.BootstrapperSequenceCompleted);
                }
            });
        }

        /// <summary>
        /// 
        /// </summary>
        public void Run()
        {
            Run(true);
        }
    }
}
